﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using repliback4.Net.Protocol;


namespace repliback4.XmlStreaming {

    class MyStreamWriter : TextWriter {
        public MyStreamWriter ( )
            : base( ) {

        }

        public override Encoding Encoding {
            get { throw new NotImplementedException( ); }
        }
    }

    public class XmlStreamException : Exception {
        public XmlStreamException ( String message ) : base( message ) { }
    }

    public class XmlStreamWriterSettings {
        /// <summary>
        /// 
        /// </summary>
        public Boolean AutoFlush = true;
        public Boolean NiceFormating = true;
        public Encoding Encoding = Encoding.UTF8;
        public static XmlStreamWriterSettings Default {
            get {
                XmlStreamWriterSettings defaultSettings = new XmlStreamWriterSettings( );

                return defaultSettings;
            }
        }
    }
    public class XmlStreamReaderSettings {
        public static XmlStreamReaderSettings Default {
            get {
                XmlStreamReaderSettings defaultSettings = new XmlStreamReaderSettings( );

                return defaultSettings;
            }
        }
    }


    public class XmlStreamWriter {
        #region Protected fields
        protected TextWriter masterWriter;

        protected XmlNamespaceManager nsManager;
        protected XmlDocument xDoc;
        protected XmlWriter xmlWriter;
        protected XmlWriter elementWriter;
        protected XmlWriterSettings xwrts;
        //protected StanzaSerializer stanzaSerializer;
        protected Boolean documentOpened = false;

        protected XmlStreamWriterSettings settings;
        protected Stack<StreamContext> streamContext;
        #endregion
        #region Public Properies
        public XmlStreamWriterSettings Settings {
            get {
                if ( this.settings == null ) {
                    this.settings = XmlStreamWriterSettings.Default;
                }
                return this.settings;
            }
            set {
                //if ( this.settings == null ) {
                this.settings = value;
                //} else {
                //    throw new Exception( "cant change settings" );
                //}
            }
        }

        public XmlDocument Document {
            get { return this.xDoc; }
        }
        public XmlNamespaceManager NamespaceManager {
            get {
                return this.nsManager;
            }
        }

        public TextWriter Writer {
            set { this.masterWriter = value; }
            get { return this.masterWriter; }
        }

        public Boolean DocumentOpened {
            get {
                return documentOpened;
            }
        }
        #endregion
        #region Constructors

        public XmlStreamWriter ( ) {
            this.init( );
        }
        public XmlStreamWriter ( TextWriter textWriter ) {
            //this.xDoc = document;
            this.Writer = textWriter;
            this.init( );
        }

        //public XmlStreamWriter ( TextWriter textWriter, XmlStreamWriterSettings settings ) {
        //    //this.xDoc = document;
        //    this.masterWriter = textWriter;
        //    this.settings = settings;
        //    this.init( );
        //}

        //public XmlStreamWriter ( TextWriter textWriter, XmlStreamWriterSettings settings, XmlNamespaceManager namespaceManager ) {
        //    //this.xDoc = document;
        //    this.masterWriter = textWriter;
        //    this.settings = settings;
        //    this.nsManager = namespaceManager;
        //    this.init( );
        //}



        protected void init ( ) {
        }
        #endregion
        #region Open / close stream

        public XmlDocument OpenDocument ( ) {
            this.xDoc = new XmlDocument( );
            this.xwrts = new XmlWriterSettings( );
            //this.xwrts.ConformanceLevel = ConformanceLevel.Fragment;
            this.xwrts.ConformanceLevel = ConformanceLevel.Document;
            //this.xwrts.OmitXmlDeclaration = false;
            this.xwrts.CloseOutput = false;

            if ( this.Settings.NiceFormating ) {
                this.xwrts.Indent = true;
                this.xwrts.NewLineChars = "\n";
                this.xwrts.NewLineOnAttributes = false;
                //this.xwrts.IndentChars = "\t";
                //this.xwrts.NewLineHandling = NewLineHandling.None;
            }
            xwrts.Encoding = this.Settings.Encoding;

            this.xmlWriter = XmlTextWriter.Create( this.Writer, xwrts );

            this.xmlWriter.WriteStartDocument( );
            this.xmlWriter.Flush( );
            this.documentOpened = true;

            xwrts.ConformanceLevel = ConformanceLevel.Fragment;

            this.elementWriter = XmlTextWriter.Create( this.Writer, xwrts );

            this.streamContext = new Stack<StreamContext>( );
            return this.xDoc;
        }

        public void OpenStream ( Net.Protocol.Messages.BaseStream stream ) {

            if ( !this.DocumentOpened ) {
                throw new XmlStreamException( "Document not opened, use first XmlStreamWriter.OpenDocument()" );
            }
            if ( this.streamContext.Count > 0 ) {
                this.streamContext.Peek( ).stream.Xml.AppendChild( stream.Xml );
            } else {
                this.Document.AppendChild( stream.Xml );
            }

            this.elementWriter.WriteStartElement(
                    stream.Xml.Prefix,
                    stream.Xml.LocalName,
                    stream.Xml.NamespaceURI );

            foreach ( XmlAttribute attr in stream.Xml.Attributes ) {
                this.elementWriter.WriteAttributeString( attr.LocalName, attr.NamespaceURI, attr.Value );
            }
            //XmlSpace
            if ( stream.Xml.NamespaceURI != "" ) {
                if ( stream.Xml.Prefix != "" ) {
                    this.elementWriter.WriteAttributeString( "xmlns", stream.Xml.Prefix, this.xDoc.GetNamespaceOfPrefix( "xmlns" ), stream.Xml.NamespaceURI );
                } else {
                    this.elementWriter.WriteAttributeString( "xmlns", this.xDoc.GetNamespaceOfPrefix( "xmlns" ), stream.Xml.NamespaceURI );
                }
            }

            this.elementWriter.WriteWhitespace( "" );
            StreamContext sContext = new StreamContext( );
            sContext.stream = stream;


            this.streamContext.Push( sContext );
        }

        public void CloseStream ( ) {
            this.elementWriter.WriteFullEndElement( );
            this.streamContext.Pop( );
            //this.elementWriter.Flush( );
            // this.streamOpened = false;
        }
        #endregion
        #region Write
        public void WriteStanza ( Net.Protocol.Messages.Stanza stanza ) {

            if ( this.streamContext.Count < 1 ) {
                throw new XmlStreamException( "no stream context, open stream first" );
            }

            StreamContext sCtx = this.streamContext.Peek( );
            repliback4.Net.Protocol.Messages.BaseStream stream = sCtx.stream;
            stream.Xml.AppendChild( stanza.Xml );
            
            stanza.Xml.WriteTo( this.elementWriter );
            //if ( this.Settings.AutoFlush ) this.elementWriter.Flush( );

        }

        public void Flush ( ) {
            this.elementWriter.Flush( );
        }
        #endregion

    }
    /*
    /// <summary>
    /// 
    /// </summary>
    public class XmlStreamReader {
        #region Protected fields
        protected XmlDocument masterDocument;
        protected TextReader masterReader;
        protected XmlStreamReaderSettings settings;
        protected XmlNamespaceManager nsManager;
        #endregion

        #region Constructors
        /// <summary>
        /// 
        /// </summary>
        /// <param name="textReader">textreader</param>
        /// <param name="document">master document</param>
        public XmlStreamReader ( TextReader textReader, XmlDocument document ) {
            this.masterReader = textReader;
            this.masterDocument = document;
            this.settings = XmlStreamReaderSettings.Default;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="textReader"></param>
        /// <param name="document"></param>
        /// <param name="settings"></param>
        public XmlStreamReader ( TextReader textReader, XmlDocument document, XmlStreamReaderSettings settings ) {
            this.masterReader = textReader;
            this.masterDocument = document;
            this.settings = settings;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="textReader"></param>
        /// <param name="document"></param>
        /// <param name="settings"></param>
        /// <param name="namespaceManager"></param>
        public XmlStreamReader ( TextReader textReader, XmlDocument document, XmlStreamReaderSettings settings, XmlNamespaceManager namespaceManager ) {
            this.masterReader = textReader;
            this.masterDocument = document;
            this.settings = settings;
            this.nsManager = namespaceManager;
        }
        #endregion

        #region Open / Close Stream
        public void OpenStream ( ) { 
        
        }

        public void CloseStream ( ) { 
        
        }
        #endregion


    }*/
}
